package com.ruoyi.sale.service.impl;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.commodity.domain.Product;
import com.ruoyi.commodity.domain.ProductImage;
import com.ruoyi.commodity.mapper.AuthBrandMapper;
import com.ruoyi.commodity.mapper.ProductImageMapper;
import com.ruoyi.commodity.mapper.ProductMapper;
import com.ruoyi.common.api.ordersProduct.OrdersProductApi;
import com.ruoyi.common.api.procured.ProcuredApi;
import com.ruoyi.common.api.procured.dto.ProcuredPlanDto;
import com.ruoyi.common.api.procuredOrders.ProcuredOrdersApi;
import com.ruoyi.common.api.procuredProduct.ProcuredProductApi;
import com.ruoyi.common.api.procuredProduct.dto.ProcuredProductDto;
import com.ruoyi.common.api.sale.plan.SalePlanApi;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AuthBrand;
import com.ruoyi.common.core.domain.OrdersProduct;
import com.ruoyi.common.core.domain.ProcuredOrders;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.sale.domain.*;
import com.ruoyi.sale.domain.ApprovalProcess;
import com.ruoyi.sale.mapper.*;
import com.ruoyi.sale.urtl.AncestorsProcessor;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.template.domain.TemplateDetail;
import com.ruoyi.template.mapper.TemplateMapper;
import com.ruoyi.template.service.TemplateDetailService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.sale.service.IPlanService;
import org.springframework.util.NumberUtils;

import static com.ruoyi.common.utils.PageUtils.startPage;

/**
 * 销售计划Service业务层处理
 *
 * @author ruoyi
 * @date 2023-10-13
 */
@Service
public class PlanServiceImpl implements IPlanService, SalePlanApi {
	@Autowired
	private PlanMapper planMapper;
	@Autowired
	private ApprovalProcessMapper approvalProcessMapper;

	@Autowired
	private AuthBrandMapper authBrandMapper;

	@Autowired
	private ProductImageMapper productImageMapper;

	@Autowired
	private SysMenuMapper sysMenuMapper;

	@Autowired
	private TemplateMapper templateMapper;

	@Autowired
	private TemplateDetailService templateDetailService;

	@Autowired
	private SysUserRoleMapper sysUserRoleMapper;

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private PlanProcessMapper planProcessMapper;

	@Autowired
	private PlanProcessLogMapper planProcessLogMapper;

	@Autowired
	private ProductMapper productMapper;

	@Autowired
	private ShipmentsProductMapper shipmentsProductMapper;

	@Autowired
	private ProcuredApi procuredApi;

	@Autowired
	private ProcuredProductApi procuredProductApi;

	@Autowired
	private ProcuredOrdersApi procuredOrdersApi;

	@Autowired
	private OrdersProductApi ordersProductApi;


	/**
	 * 查询销售计划
	 *
	 * @param id 销售计划主键
	 * @return 销售计划
	 */
	@Override
	public Plan selectPlanById(Long id) {
		// 查询单条计划记录
		Plan plan = planMapper.selectPlanById(id);
		if (plan == null) {
			return null;
		}
		Long[] list = new Long[]{plan.getId()};

		// 查询该计划关联的产品信息
		List<ShipmentsProduct> shipmentsProducts = planMapper.selectShipmentsProductById(new Long[]{plan.getId()},false);

		if (!shipmentsProducts.isEmpty()) {
			// 提取去重后的产品ID列表
			List<Long> productIds = shipmentsProducts.stream()
					.map(ShipmentsProduct::getProductId)
					.distinct()
					.collect(Collectors.toList());

			// 查询产品图片，并构造产品ID到图片路径列表的映射
			Map<Integer, List<String>> imageMap = productIds.isEmpty()
					? new HashMap<>()
					: productImageMapper.selectProductImagesByProductId(productIds)
					.stream()
					.collect(Collectors.toMap(
							ProductImage::getProductId,
							productImage -> Collections.singletonList(productImage.getProductImagePath()),
							(existing, replacement) -> existing
					));

			// 绑定产品图片到对应的产品中
			shipmentsProducts.forEach(product -> {
				List<String> images = imageMap.get(product.getProductId().intValue());
				if (images != null && !images.isEmpty()) {
					product.setImgName(images);
				}
			});
		}

		// 将查询到的产品信息设置到计划对象中
		plan.setShipmentsProductList(shipmentsProducts);
		return plan;
	}


//	@Override
//	public List<Plan> selectPlanList(Plan plan) {
//		List<Plan> planList = planMapper.selectPlanList(plan);
//
//		// 首先获取所有计划的ID集合
//		Long[] longArray = planList.stream().map(Plan::getId).toArray(Long[]::new);
//		if (longArray.length != 0) {
//			// 一次性查询所有计划的关联产品信息
//			List<ShipmentsProduct> shipmentsProducts = planMapper.selectShipmentsProductById(longArray);
//			// 提取所有的产品id
//			List<Long> collect = shipmentsProducts.stream().map(ShipmentsProduct::getProductId).collect(Collectors.toList());
//			// 查询出所有的产品图片并按照产品id进行分组
//			Map<Integer, List<String>> imageList = productImageMapper.selectProductImagesByProductId(collect).stream()
//					.collect(Collectors.groupingBy(
//							ProductImage::getProductId, // 根据 ProductId 分组
//							Collectors.mapping(ProductImage::getProductImagePath, Collectors.toList()) // 将每个组内的 ProductImagePath 收集为列表
//					));
//			// 将对应的图片设置到计划对象中
//			shipmentsProducts.forEach(
//					a -> {
//						a.setImgName(imageList.get(a.getProductId().intValue()).get(0));
//					}
//			);
//			// 将产品信息按照计划ID进行分组
//			Map<Long, List<ShipmentsProduct>> shipmentsProductMap = shipmentsProducts.stream()
//					.collect(Collectors.groupingBy(ShipmentsProduct::getPlanId));
//			// 将产品信息设置到计划对象中
//			for (Plan newPlan : planList) {
//				List<ShipmentsProduct> productList = shipmentsProductMap.get(newPlan.getId());
//				newPlan.setShipmentsProductList(productList);
//			}
//			return planList;
//		}
//		return planList;
//	}

	/**
	 * 查询销售计划列表
	 *
	 * @param plan 销售计划
	 * @return 销售计划
	 */
	@Override
	public List<Plan> selectPlanList(Plan plan,Boolean flag) {

		// 如果有SKU查询条件，先查询符合条件的销售计划ID
		if (plan.getSearchSku() != null && !plan.getSearchSku().trim().isEmpty()) {
			List<Long> planIds = planMapper.selectPlanIdsBySku(plan.getSearchSku());
			if (planIds.isEmpty()) {
				return new ArrayList<>(); // 没有符合条件的计划，直接返回空列表
			}
			// 将查询到的计划ID设置到查询条件中
			plan.setPlanIds(planIds);
		}

		List<Plan> planList = planMapper.selectPlanList(plan);

		// 如果查询没有结果，直接返回空列表
		if (planList == null || planList.isEmpty()) {
			return new ArrayList<>();
		}

		// 获取所有计划的ID集合
		Long[] longArray = planList.stream()
				.map(Plan::getId)
				.toArray(Long[]::new);

		// 一次性查询所有计划的关联产品信息
//		List<ShipmentsProduct> result = planMapper.selectShipmentsProductById(longArray);
		List<ShipmentsProduct> shipmentsProducts = planMapper.selectShipmentsProductById(longArray,flag);
//		List<ShipmentsProduct> shipmentsProducts = Boolean.TRUE.equals(plan.getFlag())
//				? mergeShipmentsProducts(result)
//				: result;

		// 提取所有的产品id
		List<Long> collect = shipmentsProducts.stream()
				.map(ShipmentsProduct::getProductId)
				.distinct() // 避免重复产品ID，优化查询
				.collect(Collectors.toList());

		// 使用三目运算符直接赋值，保证 imageList 为 final（实际上不会再被赋值）
		Map<Integer, List<String>> imageList = !collect.isEmpty()
				? productImageMapper.selectProductImagesByProductId(collect).stream()
				.collect(Collectors.toMap(
						ProductImage::getProductId,
						productImage -> new ArrayList<>(Collections.singletonList(productImage.getProductImagePath())),
						(existing, replacement) -> {
							existing.addAll(replacement); // 将后续出现相同productId的图片添加到原有的图片集合中去
							return existing;
						}
				))
				: new HashMap<>();

		// 将产品信息按照计划ID进行分组
		Map<Long, List<ShipmentsProduct>> shipmentsProductMap = shipmentsProducts.stream()
				.collect(Collectors.groupingBy(ShipmentsProduct::getPlanId));

		// 将产品信息和图片设置到计划对象中
		planList.forEach(planItem -> {
			List<ShipmentsProduct> productList = shipmentsProductMap.get(planItem.getId());
			if (productList != null) {
				// 将图片和产品信息绑定
				productList.forEach(product -> {
					// 获取产品对应的图片，若没有图片则设置默认值
					List<String> images = imageList.get(product.getProductId().intValue());
					if (images != null && !images.isEmpty()) {
						product.setImgName(images);
					}
				});
				planItem.setShipmentsProductList(productList);
			}
		});

		return planList;
	}

	public static List<ShipmentsProduct> mergeShipmentsProducts(List<ShipmentsProduct> list) {
		Map<String, ShipmentsProduct> map = new LinkedHashMap<>();
		for (ShipmentsProduct sp : list) {
			String key = sp.getPlanId() + "_" + sp.getProductId();
			if (!map.containsKey(key)) {
				ShipmentsProduct merged = new ShipmentsProduct();
				BeanUtils.copyProperties(sp, merged);
				merged.setSentSize(sp.getSentSize());
				merged.setOperSize(sp.getOperSize());
				merged.setPlanSize(sp.getPlanSize());
				merged.setAmount(sp.getAmount());
				merged.setGtins(new ArrayList<>());
				merged.getGtins().add(sp.getGtin());  // 假设初始对象 sp.gtins 已包含单个 gtin
				map.put(key, merged);
			} else {
				ShipmentsProduct merged = map.get(key);
				merged.setSentSize(merged.getSentSize() + sp.getSentSize());
				merged.setOperSize(merged.getOperSize() + sp.getOperSize());
				merged.setPlanSize(merged.getPlanSize() + sp.getPlanSize());
				merged.setAmount(merged.getAmount().add(sp.getAmount()));

				if (sp.getProductRemarks() != null && !sp.getProductRemarks().isEmpty()) {
					String exist = merged.getProductRemarks();
					merged.setProductRemarks(
							(exist == null || exist.isEmpty()) ? sp.getProductRemarks()
									: exist + "," + sp.getProductRemarks()
					);
				}
				merged.getGtins().add(sp.getGtin());
			}
		}
		return new ArrayList<>(map.values());
	}


	/**
	 * 新增销售计划
	 *
	 * @param plan 销售计划
	 * @return 结果
	 */
	@Transactional
	@Override
	public int insertPlan(Plan plan, String componentPath, Long userId) {
		// 获取当前日期和时间
		LocalDateTime now = LocalDateTime.now();

		// 格式化日期和时间，生成字符串表示
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String date_time = now.format(formatter);

		// 将字符串转换为Date类型
		Date date = new Date();
		try {
			date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date_time);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		plan.setPreparationTime(date);
		plan.setPlanNumber(generateCode());
		plan.setCreateTime(new Date());
		plan.setCreateBy(SecurityUtils.getNickname());
		plan.setUpdateTime(new Date());
		int rows = planMapper.insertPlan(plan);
		insertShipmentsProduct(plan);

		//检查审核流程模版
		checkTemplate(componentPath, userId, plan);

		return rows;
	}

	//检查审核流程模版
	@Transactional
	public void checkTemplate(String componentPath, Long userId, Plan plan) {
		//获取菜单ID
		SysMenu sysMenu = sysMenuMapper.selectMenuByComponent(componentPath);
		if (sysMenu == null) {
			throw new ServiceException("获取菜单ID失败，请刷新页面重新操作。");
		}

		//校验当前菜单和用户是否绑定
		String templateId = templateMapper.findTemplateIdByUserIdAndMenuId(userId, sysMenu.getMenuId());
		if (StringUtils.isNull(templateId) || templateId == null) {
			throw new ServiceException("未匹配到对应的审核模板，请联系人事匹配后再操作。");
		}

		//获取模板详情
		List<TemplateDetail> templateDetails = templateDetailService.getTemplateDetailList(templateId);
		if (templateDetails.isEmpty() || templateDetails == null) {
			throw new ServiceException("获取模板详情失败。");
		}

		TemplateDetail firstDetail = templateDetails.get(0);
		Long reviewerUserId = Long.valueOf(firstDetail.getReviewerId());

		plan.setReviewerUserId(reviewerUserId);
		//更新当前审核人用户
		planMapper.updatePlanReviewerUserId(plan);

		//新增销售计划审核模版
		insertPlanProcess(plan.getId(), templateDetails, userId);

	}

	//新增销售计划审核模版
	private void insertPlanProcess(Long planId, List<TemplateDetail> templateDetails, Long userId) {

		// 1. 删除旧的流程（如果有）
		LambdaQueryWrapper<PlanProcess> deleteWrapper = new LambdaQueryWrapper<>();
		deleteWrapper.eq(PlanProcess::getPlanId, planId);
		planProcessMapper.delete(deleteWrapper);

		//2. 插入新的审核流程
		for (TemplateDetail td : templateDetails) {

			String UUID = IdUtils.fastSimpleUUID();
			String processStatus = Constants.PLAN_PROCESS_STATUS_PENDING;
			Date processTime = DateUtils.getNowDate();

			Long reviewerId = Long.valueOf(td.getReviewerId());
			SysUser user = sysUserMapper.selectUserById(reviewerId);
			Long reviewerDeptId = user.getDeptId();

			LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.eq(SysUserRole::getUserId, reviewerId);
			SysUserRole sur = sysUserRoleMapper.selectOne(queryWrapper);
			Long reviewerRoleId = sur.getRoleId();

			Integer reviewerOrder = td.getReviewOrder();

			PlanProcess pp = new PlanProcess(UUID, processStatus, planId, reviewerId, reviewerDeptId, reviewerRoleId, reviewerOrder);
			planProcessMapper.insert(pp);
		}
		//插入审核流程表日志
		SysUser _user = sysUserMapper.selectUserById(userId);
		savePlanProcessLog(planId, Constants.PLAN_PROCESS_STATUS_PUT, _user.getNickName(), "");
	}

	/**
	 * 插入审核流程表日志
	 *
	 * @return
	 */
	private void savePlanProcessLog(Long planId, String logStatus, String nickName, String logRemark) {
		PlanProcessLog log = new PlanProcessLog(IdUtils.fastSimpleUUID(), planId,
				logStatus, nickName, logRemark, DateUtils.getNowDate());
		planProcessLogMapper.insert(log);
	}

	/**
	 * 生成随机数
	 *
	 * @return
	 */
	public String generateCode() {
		// 获取当前日期
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
		String currentDate = dateFormat.format(new Date());
		// 获取序列号
		String planNumber = planMapper.selectPlanNumber();
		String randomNumber;
		// ...根据自己的业务逻辑实现获取序列号的方法
		if (StringUtils.isEmpty(planNumber)) {
			randomNumber = Constants.RANDOM_NUMBERS;
		} else {
			randomNumber = String.format("%04d", (NumberUtils.parseNumber(planNumber.substring(9), Long.class) + 1));
		}

		// 拼接生成的代码
		String code = Constants.CODE_SALE + currentDate + randomNumber;

		return code;
	}

	/**
	 * 修改销售计划
	 *
	 * @param plan 销售计划
	 * @return 结果
	 */
	@Transactional
	@Override
	public int updatePlan(Plan plan) {
		plan.setUpdateTime(DateUtils.getNowDate());
		plan.setPlanStatus("6"); // 未审核状态
		planMapper.deleteShipmentsProductByPlanId(plan.getId());
		insertShipmentsProduct(plan);
		return planMapper.updatePlan(plan);
	}

	/**
	 * 批量删除销售计划
	 *
	 * @param ids 需要删除的销售计划主键
	 * @return 结果
	 */
	@Transactional
	@Override
	public int deletePlanByIds(Long[] ids) {
		planMapper.deleteShipmentsProductByPlanIds(ids);
		return planMapper.deletePlanByIds(ids);
	}

	/**
	 * 删除销售计划信息
	 *
	 * @param id 销售计划主键
	 * @return 结果
	 */
	@Transactional
	@Override
	public int deletePlanById(Long id) {
		planMapper.deleteShipmentsProductByPlanId(id);
		return planMapper.deletePlanById(id);
	}

	@Override
	public List<ShipmentsProduct> selectShipmentsProductById(Long[] ids) {
		return planMapper.selectShipmentsProductById(ids,false);
	}

	@Override
	public int updatePlanStatusById(Long id) {
		return planMapper.updatePlanStatusById(id);
	}

	@Override
	public List<Plan> selectPostUserDept(Long userId, Long deptId, Long id) {
		String ancestorsStr = planMapper.selectAncestors(userId);
		AncestorsProcessor processor = new AncestorsProcessor();
		Long[] deptIds = processor.extractAncestors(ancestorsStr);
		List<Plan> plans = planMapper.selectPostUserDept(deptIds);
		ApprovalProcess approvalProcess = new ApprovalProcess();
		approvalProcess.setThisUser(userId);
		approvalProcess.setPlanId(id);
		plans.stream()
				.map(newPlan -> {
					BeanUtils.copyProperties(newPlan, approvalProcess);
					return approvalProcess;
				})
				.filter(approvalProc -> approvalProcessMapper.selectApprovalProcessList(approvalProc).size() == 0)
				.forEach(approvalProc -> approvalProcessMapper.insertApprovalProcess(approvalProc));
		return plans;
	}


	@Override
	public int updateStatus(ApprovalProcess approvalProcessN) {
		ApprovalProcess approvalProcess = new ApprovalProcess();
		approvalProcess.setPlanId(approvalProcessN.getPlanId());
		List<ApprovalProcess> approvalProcesses = approvalProcessMapper.selectApprovalProcessList(approvalProcess);
		boolean allStatusIsOne = true;  // 标志位，初始值为true
		for (ApprovalProcess newApprovalProcess : approvalProcesses) {
			if (!newApprovalProcess.getStatus().equals("1")) {
				if (newApprovalProcess.getStatus().equals("2")) {
					allStatusIsOne = true;
					break;
				}
				allStatusIsOne = false;
			}
		}
		String planStatus = approvalProcessN.getFlag() ? "1" : "0";
		if (allStatusIsOne) {
			// 执行其他逻辑
			return planMapper.updateStatus(planStatus, approvalProcess.getPlanId());
		}
		return 0;
	}

	@Override
	public List<Plan> selectPlanReviewed(Plan plan) {
		return planMapper.selectPlanReviewed(plan);
	}

	@Override
	public List<Plan> selectPlanInitiated(Long userId) {
		return planMapper.selectPlanInitiated(userId);
	}

	@Override
	public List<ProductAuth> selectItemPlan(ProductAuth productAuth) {

		// 查询出店铺下的所有品牌
		List<AuthBrand> authBrands = authBrandMapper.selectBrandList(productAuth.getAuthId());

		// 提取出该店铺下所有的品牌id
		List<Long> authBrandIds = authBrands.stream().map(AuthBrand::getAuthBrandId).collect(Collectors.toList());

		productAuth.setAuthBrandIds(authBrandIds);
		// 调用分页查询：注意这里只调用一次 PageHelper.startPage
//		PageHelper.startPage(productAuth.getPageNum(), productAuth.getPageSize());
		startPage();
		// 查询出对应的产品数据
		List<ProductAuth> productAuths = planMapper.selectItemPlan(productAuth);

		//提取所有的产品id查询出对应的产品图片
		List<Long> productIds = productAuths.stream().map(ProductAuth::getProductId).collect(Collectors.toList());

		if (!productIds.isEmpty()) {
			List<ProductImage> productImages = productImageMapper.selectProductImagesByProductId(productIds);

			// 按照产品ID进行分组，并提取每个产品图片的imagePath作为值
			Map<Integer, List<String>> collect = productImages.stream()
					.collect(Collectors.groupingBy(
							ProductImage::getProductId,
							Collectors.mapping(ProductImage::getProductImagePath, Collectors.toList())
					));

			// 将图片数据封装到对应的产品中去
			productAuths.forEach(
					item -> item.setImgName(collect.get(item.getProductId().intValue()))
			);
		}
//		// 用 PageInfo 包装原始列表，此时 PageInfo 内部已包含正确的 total 值
//		PageInfo<ProductAuth> pageInfo = new PageInfo<>(productAuths);
//		// 更新转换后的列表
//		pageInfo.setList(productAuths);
//		return pageInfo;
		return productAuths;
	}

	@Override
	public List<ProductAuth> selectPairId(Plan plan) {
		return planMapper.selectPairId(plan);
	}

	/**
	 * 待我审核的销售计划
	 *
	 * @param plan
	 * @return 结果
	 */
	@Override
	public List<Plan> getPlanWaitProcessList(Plan plan) {
		return planMapper.getPlanWaitProcessList(plan);
	}

	/**
	 * 撤回销售计划
	 */
	@Override
	@Transactional
	public int revokePlan(Plan plan, String nickname, Long userId, String componentPath) {

		//插入撤回日志
		savePlanProcessLog(plan.getId(), Constants.PLAN_PROCESS_STATUS_BACK, nickname, plan.getRemark());

		//检查审核流程模版
		checkTemplate(componentPath, userId, plan);

		plan.setPlanStatus(Constants.PLAN_PROCESS_STATUS_NOCHECK);//未审核

		return planMapper.updateById(plan);
	}

	/**
	 * 提前结束销售计划
	 *
	 * @return
	 */
	@Override
	@Transactional
	public int endPlanById(Long planId, String detailId, Integer count) {
		// 检查销售计划明细信息
		ShipmentsProduct shipmentsProduct = shipmentsProductMapper.selectOne(
				new LambdaQueryWrapper<ShipmentsProduct>()
						.eq(ShipmentsProduct::getId, detailId)
						.eq(ShipmentsProduct::getDeleteStatus, 0)
		);


		if (shipmentsProduct == null) {
			throw new ServiceException("未找到对应的销售计划明细");
		}
		if (count > shipmentsProduct.getPlanSize()) {
			throw new ServiceException("发货数量不能够大于计划数量");
		}
		if (shipmentsProduct.getTerminatedQuantity() != null && shipmentsProduct.getRelatedReturnPurchaseOrderId() != null) {
			throw new ServiceException("该销售计划明细已经结束！");
		}

		// 获取销售计划编号(减少一次查询，只查询需要的字段)
		String planNumber = planMapper.selectOne(
				new LambdaQueryWrapper<Plan>()
						.eq(Plan::getId, planId)
						.select(Plan::getPlanNumber)
		).getPlanNumber();

		// 查询相关联的采购计划
		List<ProcuredPlanDto> procuredPlans = procuredApi.selectProcuredByPlanId(planNumber, shipmentsProduct.getProductId());

		// 原计划数量减去用户修改的发货数量等于要结束的数量
		int terminatedQuantity = shipmentsProduct.getPlanSize().intValue() - count;
		String terminationRemark = String.format(
				"原计划数量%1$d个，需结束数量%2$d个，结束后的数量%3$d个",
				shipmentsProduct.getPlanSize(), // 原计划数量
				terminatedQuantity,             // 需结束数量
				count                           // 结束后的数量
		);
		StringBuilder orderIds = new StringBuilder(); // 用于拼接订单ID


		if (!procuredPlans.isEmpty()) {
			Long productId = shipmentsProduct.getProductId();
			// 获取所有采购计划ID (避免在循环中多次创建集合)
			List<Long> planIds = procuredPlans.stream()
					.map(ProcuredPlanDto::getPlanId)
					.collect(Collectors.toList());
			// 要是销售明细没有被采购过则直接进行关闭，要是被采购过就存储对应的关闭数量并修改计划数量为输入的发货数量
			// 查询对应的采购订单
			List<ProcuredOrders> ordersList = procuredOrdersApi.selectOrdersId(planIds, productId);
			// 查询对应的采购商品信息
			List<ProcuredProductDto> procuredProductList = procuredProductApi.selectList(planIds, productId);
			if (ordersList.isEmpty()) {
				// TODO 这里是创建了采购计划但是没有下过单的处理逻辑
				// 首先校验采购数量有多少，是否超出了需要结束数量，如果超出就需要修改新的采购量，没有超出的话按照流程继续能够进行采购剩下来的产品
//				List<ProcuredProductDto> procuredProductList = procuredProductApi.selectList(planIds,productId);
				int remainingCount = count; // 结束数量之后的发货数量
				int totalNumber = procuredProductList.stream() //汇总所有的采购数量
						.mapToInt(ProcuredProductDto::getNumber)  // 提取每个元素的 'number' 字段
						.sum();  // 汇总所有 'number' 字段的值

				if (totalNumber > remainingCount) {
					int result = totalNumber - remainingCount; // 这里就是需要回滚掉的采购数量
					for (ProcuredProductDto procuredProductDto : procuredProductList) {
						Integer number = procuredProductDto.getNumber();  // 采购数量
						int min = Math.min(number, result);
						result -= min;
						// 且要调整采购数量
						int i = procuredProductApi.updateProcuredProduct(procuredProductDto.getId(), number - min);
						if (i <= 0) {
							throw new ServiceException("修改采购商品采购数量失败！");
						}
						// 相应调整采购计划的总件数
						int p = procuredApi.updateTotal(procuredProductDto.getPlanId(), number - min);
						if (p <= 0) {
							throw new ServiceException("修改采购计划总数量失败！");
						}
						// 拼接订单ID，使用逗号分隔
						if (orderIds.length() > 0) {
							orderIds.append(",");
						}
						orderIds.append(procuredProductDto.getPlanId()); // 记录参与分配的采购计划id
						shipmentsProduct.setTerminationRemark("采购计划：" + procuredProductDto.getPlanId() + "参与分配了" + min + "个。");
						shipmentsProduct.setProcuredSelectedCount(shipmentsProduct.getProcuredSelectedCount() - min);
						// 说明回滚完了
						if (result <= 0) {
							break;
						}
					}
					// 处理拼接后的订单ID，可以根据业务需要保存或用于后续操作
					String assignedOrderIds = orderIds.toString(); // 拼接好的订单ID字符串
					shipmentsProduct.setRelatedReturnPurchaseOrderId(assignedOrderIds);
				}
				if (totalNumber >= remainingCount) {
					shipmentsProduct.setSelectStatus("1"); // 如果说原来的采购数量大于或者等于结束后的发货数量则需要结束掉不能够进行采购了
				}

				// 更新销售计划明细的状态
				shipmentsProduct.setTerminatedQuantity(terminatedQuantity);
				shipmentsProduct.setPlanSize(count.longValue()); // 结束之后的发货数量就是新的计划数量
				shipmentsProduct.setToBeTerminatedQuantity(0); // 这里应该是没有剩余结束数量的，要么就是采购订单退货一部分或者退完，要么就是直接结束掉
				shipmentsProduct.setTerminationRemark(shipmentsProduct.getTerminationRemark() + " || 这里结束数量关联的Id是采购计划Id");
				// 执行更新操作
				shipmentsProductMapper.updateById(shipmentsProduct);
			} else {
				// TODO 这里是创建了采购计划且已经下过单的处理逻辑
				List<Long> ordersIds = ordersList.stream().map(ProcuredOrders::getOrdersId).collect(Collectors.toList());
				// 要是有采购订单则需要查询所有的采购订单的产品下单数量
				List<OrdersProduct> ordersProducts = ordersProductApi.selectList(ordersIds, productId);
				int totalOrderQuantity = ordersProducts.stream() // 这里进行汇总的是所有的已下单数量
						.mapToInt(item -> item.getTransferableNumber().intValue())
						.sum();
				if (totalOrderQuantity > count) {
					// 如果已下单的数量大于结束后的发货数量就说明需要有一部分货要退掉
					int result = totalOrderQuantity - count;
					for (OrdersProduct ordersProduct : ordersProducts) {
						Long transferableNumber = ordersProduct.getTransferableNumber(); // 采购数量

						long assignQuantity = Math.min(result, transferableNumber); // 分配给当前订单的结束数量
						result -= assignQuantity; // 更新剩余的需要结束的数量

						// 拼接订单ID，使用逗号分隔
						if (orderIds.length() > 0) {
							orderIds.append(",");
						}
						orderIds.append(ordersProduct.getOrdersId()); // 记录参与分配的订单ID

						// 更新采购商品明细待退货数量
						int a = ordersProductApi.updateReturnPendingQuantity(ordersProduct.getId(), assignQuantity);
						if (a <= 0) {
							throw new ServiceException("更新采购订单商品详细待到货数量失败！");
						}
						// 如果剩余的需要的结束数量已经分配完，退出循环
						if (result <= 0) {
							break;
						}
					}
					shipmentsProduct.setSelectStatus("1"); // 如果说原来的采购数量大于或者等于结束后的发货数量则需要结束掉不能够进行采购了
				} else {
					// 要是没有下完就需要看还能下多少个，调整采购数量
					int totalNumber = procuredProductList.stream() //汇总所有的采购数量
							.mapToInt(ProcuredProductDto::getNumber)  // 提取每个元素的 'number' 字段
							.sum();  // 汇总所有 'number' 字段的值
					int remainingOrderQuantity = count - totalOrderQuantity;  // 这里的是可以继续下单的数量可能是0就是不能够再下单了
					int unprocuredQuantity = totalNumber - totalOrderQuantity; // 这里的是除去已下单的未采购的数量
					if (unprocuredQuantity > remainingOrderQuantity) {
						// 要是未采购的数量大于还能够继续下单的数量就需要进行回滚
						int rollbackProcurementQuantity = unprocuredQuantity - remainingOrderQuantity;
						// 将超出的未结束的数量分配到能够分配到的创建了采购计划但是还没有采购下单完的商品
						for (ProcuredProductDto procuredProductDto : procuredProductList) {
							Integer number = procuredProductDto.getNumber();  // 采购数量
							Integer turnedNumber = procuredProductDto.getTurnedNumber(); // 已采购的数量
							if (number - turnedNumber <= 0) {
								continue;
							}
							int min = Math.min(number, rollbackProcurementQuantity);
							rollbackProcurementQuantity -= min;
							int result = number - min;
							int i = procuredProductApi.updateProcuredProduct(procuredProductDto.getId(), result);
							if (i <= 0) {
								throw new ServiceException("修改采购商品采购数量失败！");
							}
							// 如果发货数量分配不够则说明这个采购商品不能够再进行下单，且要调整采购数量
							if (rollbackProcurementQuantity <= 0) {
								break;
							}
						}
					}
					if (remainingOrderQuantity <= 0) {
						shipmentsProduct.setSelectStatus("1"); // 要是剩余下单的数量小于等于0的话则说明不能够再进行下单了
					}
				}


				// 更新销售计划的备注字段
				shipmentsProduct.setTerminationRemark(terminationRemark);


				// 处理拼接后的订单ID，可以根据业务需要保存或用于后续操作
				String assignedOrderIds = orderIds.toString(); // 拼接好的订单ID字符串
				shipmentsProduct.setTerminatedQuantity(terminatedQuantity);
				shipmentsProduct.setToBeTerminatedQuantity(0); // 这里应该是没有剩余结束数量的，要么就是采购订单退货一部分或者退完，要么就是直接结束掉
				shipmentsProduct.setRelatedReturnPurchaseOrderId(assignedOrderIds);
				shipmentsProduct.setPlanSize(count.longValue()); // 更新后的计划数量
				// 执行更新操作
				shipmentsProductMapper.updateById(shipmentsProduct);
				// 6. 更新采购订单样式
				int styleUpdates = procuredOrdersApi.updateStyleClass(planIds, productId);
			}
		} else {
			// TODO 这里是没有创建过采购计划的逻辑，直接结束掉销售计划明细
			// 更新销售计划的备注字段
			shipmentsProduct.setTerminationRemark(terminationRemark);
			// 要是一个采购计划也没有的话则直接就结束掉明细
			int update = shipmentsProductMapper.update(null, new LambdaUpdateWrapper<ShipmentsProduct>()
					.set(ShipmentsProduct::getPlanSize, count)
					.set(ShipmentsProduct::getTerminatedQuantity, terminatedQuantity)
					.set(ShipmentsProduct::getToBeTerminatedQuantity, 0)
					.set(ShipmentsProduct::getSelectStatus, 1)
					.set(ShipmentsProduct::getTerminationRemark, terminationRemark)
					.eq(ShipmentsProduct::getProductId, shipmentsProduct.getProductId())
					.eq(ShipmentsProduct::getPlanId, planId)
					.eq(ShipmentsProduct::getDeleteStatus, 0)
			);
		}

		// 7. 检查该销售计划的所有明细是否都已结束
		// 1. 查询销售计划明细 - 只查询一次
		List<ShipmentsProduct> salesPlanDetails = shipmentsProductMapper.selectList(
				new LambdaQueryWrapper<ShipmentsProduct>()
						.eq(ShipmentsProduct::getPlanId, planId)
						.eq(ShipmentsProduct::getDeleteStatus, 0)
		);

		if (salesPlanDetails.isEmpty()) {
			throw new ServiceException("销售计划明细为空，请检查！");
		}

		// 2. 检查是否所有明细都已结束
		boolean allEnded = salesPlanDetails.stream()
				.allMatch(product -> "1".equals(product.getSelectStatus()));

		// 3. 如果全部已结束，更新销售计划状态
		if (allEnded) {
			planMapper.endPlanById(planId);
		}

		// 4. 批量更新明细的发货状态
		List<ShipmentsProduct> updatedDetails = new ArrayList<>();
		for (ShipmentsProduct detail : salesPlanDetails) {
			int shipped = detail.getSentSize() == null ? 0 : detail.getSentSize().intValue();
			int planned = detail.getPlanSize().intValue();

			if (shipped == planned) {
				detail.setShippingStatus(Constants.SHIPPED_STATUS); // 已发货
			} else if (shipped > 0) {
				detail.setShippingStatus(Constants.PARTIAL_SHIP_STATUS); // 部分发货
			} else {
				detail.setShippingStatus(Constants.PREPARING_STATUS); // 备货中
			}
			updatedDetails.add(detail);
		}

		// 5. 批量更新 (如果数据库支持的话)
		if (updatedDetails.size() > 0) {
			// 可以使用批量更新方法 (取决于你的ORM框架)
			for (ShipmentsProduct detail : updatedDetails) {
				shipmentsProductMapper.updateById(detail);
			}
		}

        // 6. 统计发货状态并更新销售计划
        // 直接使用已有数据而不再查询
		boolean allShipped = updatedDetails.stream()
				.allMatch(d -> Constants.SHIPPED_STATUS.equals(d.getShippingStatus()));
		boolean allPreparing = updatedDetails.stream()
				.allMatch(d -> Constants.PREPARING_STATUS.equals(d.getShippingStatus()));

        // 7. 更新销售计划状态
		Plan salesPlan = planMapper.selectById(planId);
		if (allShipped) {
			salesPlan.setShippingStatus(Constants.SHIPPED_STATUS);
		} else if (allPreparing) {
			salesPlan.setShippingStatus(Constants.PREPARING_STATUS);
		} else {
			salesPlan.setShippingStatus(Constants.PARTIAL_SHIP_STATUS);
		}
		planMapper.updateById(salesPlan);

		return 1;
	}

	@Override
	public List<String> SearchRelatedPurchaseOrders(String planNumber, String detailId) {
		// 查询对应的产品id根据销售计划明细id
		ShipmentsProduct shipmentsProduct = shipmentsProductMapper.selectById(detailId);
		Long productId = shipmentsProduct.getProductId(); // 产品id
		// 根据销售计划编号查询所有的采购计划
		List<ProcuredPlanDto> planList = procuredApi.selectProcuredPlan(planNumber);

		// 如果采购计划为空，直接返回空集合
		if (planList == null || planList.isEmpty()) {
			return new ArrayList<>();
		}

		// 根据所有的采购计划id和产品id查询对应的采购单
		return ordersProductApi.selectByPlanId(planList.stream().map(ProcuredPlanDto::getPlanId).collect(Collectors.toList()),productId);
	}



	/**
	 * 新增发货产品信息
	 *
	 * @param plan 销售计划对象
	 */
	public void insertShipmentsProduct(Plan plan) {
		List<ShipmentsProduct> shipmentsProductList = plan.getShipmentsProductList();
		Long planId = plan.getId();
		if (StringUtils.isNotNull(shipmentsProductList)) {
			List<ShipmentsProduct> list = new ArrayList<>();
			for (ShipmentsProduct shipmentsProduct : shipmentsProductList) {
				// 判断是否为组合 SKU（例如 "sku1+sku2" 或 "sku1*2+sku2"）
				if (shipmentsProduct.getSku() != null && shipmentsProduct.getSku().contains("+")) {
					// 拆分组合 SKU
					String[] skuParts = shipmentsProduct.getSku().split("\\+");
					// 生成唯一的组合分组ID，用于关联父记录和所有子记录
					String comboGroupId = IdUtils.fastSimpleUUID();
					// 获取组合产品的基数（组合产品的套数）
					Long openSize = shipmentsProduct.getOperSize() == null ? 0L : shipmentsProduct.getOperSize();
					// 用于累计父记录的总金额
					BigDecimal parentAmount = BigDecimal.ZERO;

					// 遍历组合 SKU 的各个部分，生成子记录
					for (String skuPart : skuParts) {
						int quantity = 1;
						String sku = skuPart;
						// 如果包含 "*" 表示该子 SKU有数量标识，例如 "sku1*2"
						if (skuPart.contains("*")) {
							String[] skuDetails = skuPart.split("\\*");
							sku = skuDetails[0];
							try {
								quantity = Integer.parseInt(skuDetails[1]);
							} catch (NumberFormatException e) {
								throw new ServiceException("解析组合sku数量出现异常，请联系管理员进行检查！");
							}
						}
						// 根据子 SKU 查询对应的产品信息
						Product subProduct = productMapper.selectBySku(sku);
						if (subProduct != null) {
							// 计算子 SKU 的实际数量：组合套数 * 子 SKU 数量
							Long totalQuantity = openSize * quantity;
							subProduct.setOperSize(totalQuantity);
							// 计算金额：单价 * 数量
							BigDecimal amount = BigDecimal.valueOf(totalQuantity).multiply(subProduct.getPrice());
							subProduct.setAmount(amount);

							// 累加到父记录的总金额中
							parentAmount = parentAmount.add(amount);

							// 构建子记录（拆分后的组合子品）
							ShipmentsProduct childRecord = new ShipmentsProduct();
							childRecord.setId(IdUtils.fastSimpleUUID());
							childRecord.setProductId(subProduct.getProductId());
							childRecord.setDeleteStatus("0");
							childRecord.setPlanId(planId);
							childRecord.setCreateTime(DateUtils.getNowDate());
							childRecord.setSku(subProduct.getSku());
							childRecord.setOperSize(subProduct.getOperSize());
							childRecord.setPlanSize(subProduct.getOperSize());
							childRecord.setSentSize(0L);
							childRecord.setAmount(subProduct.getAmount());
							childRecord.setIsCombo(0);  // 标识为组合产品的子记录
							childRecord.setComboGroupId(comboGroupId);  // 关联组合分组ID
							list.add(childRecord);
						}
					}

					// 构建组合 SKU 的父记录（保存原始组合 SKU 信息）
					ShipmentsProduct parentRecord = new ShipmentsProduct();
					parentRecord.setId(IdUtils.fastSimpleUUID());
					parentRecord.setProductId(shipmentsProduct.getProductId());
					parentRecord.setGtin(shipmentsProduct.getGtin());
					parentRecord.setSentSize(0L);
					parentRecord.setDeleteStatus("0");
					parentRecord.setPlanId(planId);
					parentRecord.setCreateTime(DateUtils.getNowDate());
					parentRecord.setSku(shipmentsProduct.getSku()); // 保存原始组合 SKU 字符串
					parentRecord.setOperSize(openSize);           // 组合产品的套数
					parentRecord.setPlanSize(openSize);
					parentRecord.setAmount(parentAmount);           // 父记录的金额为所有子记录的总和
					parentRecord.setIsCombo(1);                      // 组合产品标识
					parentRecord.setComboGroupId(comboGroupId);      // 与子记录使用相同的组合分组ID
					parentRecord.setRemark(shipmentsProduct.getProductRemarks()); // 备注
					list.add(parentRecord);
				} else {
					// 非组合 SKU，直接正常保存
					shipmentsProduct.setId(IdUtils.fastSimpleUUID());
					shipmentsProduct.setDeleteStatus("0");
					shipmentsProduct.setPlanId(planId);
					shipmentsProduct.setCreateTime(DateUtils.getNowDate());
					shipmentsProduct.setIsCombo(0);      // 普通单品
					shipmentsProduct.setComboGroupId(null);  // 无组合分组ID
					shipmentsProduct.setRemark(shipmentsProduct.getProductRemarks());
					list.add(shipmentsProduct);
				}
			}
			// 批量插入所有的 ShipmentsProduct 记录
			if (list.size() > 0) {
				planMapper.batchShipmentsProduct(list);
			}
		}
	}

	@Override
	public int updateSelectStatus(Long planId, Integer productId) {
		return planMapper.updateSelectStatus(planId,productId);
	}
}
